home *** CD-ROM | disk | FTP | other *** search
/ PC Media 20 / PC MEDIA CD20.iso / share / prog / cursoasm / cap8.msg < prev    next >
Text File  |  1993-07-16  |  12KB  |  227 lines

  1.          INTRODUCCION AL ASM: USO DE LOS PROGRAMAS ENSAMBLADORES (II)
  2.          ============================================================
  3.  
  4.    Continuamos en este octavo capítulo del curso la explicación del HELLO.ASM
  5. en el punto donde la dejamos al final del anterior capítulo.
  6.  
  7.    El último segmento del programa es el segmento de código, al que le hemos
  8. dado el nombre 'CODIGO'. La primera línea de este segmento es un ASSUME, cuya
  9. función vamos a ver detalladamente.
  10.  
  11.    Cuando vimos los distintos modos de direccionamiento, vimos que cada uno
  12. usaba un registro segmento por defecto (por cierto, uno de los registros de
  13. segmento estaba equivocado: el modo [BP+xx] usa el segmento SS por defecto, y
  14. no el DS como aparecía). Cuando queremos que una instrucción que opera por
  15. defecto con un segmento opere con otro, es necesario anteponer al operando que
  16. referencia a memoria el nombre del segmento seguido de dos puntos. Por ejemplo,
  17. veamos la siguiente instrucción, que accede al segmento apuntado por DS:
  18.  
  19.         mov ax,[0]
  20.  
  21.    Si queremos que cargue la primera palabra del segmento apuntado por CS:
  22.  
  23.         mov ax,cs:[0]
  24.  
  25.    A nivel de código de máquina, lo que se hace es prefijar la instrucción an-
  26. terior con un byte (existen cuatro posibles valores, uno para cada segmento)
  27. que especifica que no se debe usar el segmento por defecto. A este prefijo se
  28. le suele denominar 'segment override'.
  29.  
  30.    Cuando en un listado en lenguaje ensamblador se genera un acceso a memoria,
  31. el ensamblador es capaz de meter automáticamente 'segment override's donde sea
  32. necesario (además de permitirnos especificarlos a nosotros). Para ello, hay que
  33. decirle al ensamblador a cual de los segmentos que hemos definido en el listado
  34. está apuntando cada uno de los registros de segmento. Así, cuando generamos una
  35. referencia a una etiqueta, comprueba en qué segmento ha sido definida y busca
  36. cuál de los registros de segmento apunta a ése segmento. Así, puede decidir si
  37. es necesario generar un 'segment override', y cuál de ellos es necesario. la
  38. directiva 'ASSUME' dice al ensamblador a qué segmento apunta cada registro de
  39. segmento, como vemos en HELLO.ASM. De todas maneras, somos nosotros los encar-
  40. gados de hacer que, efectivamente, los registros de segmento apunten a los seg-
  41. mentos especificados.
  42.  
  43.    En caso de que el ensamblador encuentre un acceso a una etiqueta definida en
  44. un segmento no mencionado en el ASSUME, se quejará con un error del tipo
  45. 'unreachable data' ('datos inaccesibles').
  46.  
  47.    Si un segmento no va a estar apuntando a ninguno de los segmentos definidos
  48. en el listado (por ejemplo, si apunta a la memoria de vídeo), se puede añadir
  49. un ASSUME con nombre de segmento 'NOTHING', de manera que el ensamblador no
  50. asuma que el registro de segmento en cuestión permite acceder a ninguna varia-
  51. ble conocida.  Al principio del proceso de ensamblado, el ensamblador está como
  52. si hubiera leído una línea así:
  53.  
  54.     ASSUME CS:NOTHING, DS:NOTHING, ES:NOTHING, SS:NOTHING
  55.  
  56.    Es importante comprender el funcionamiento de la directiva ASSUME, ya que
  57. puede causar confusiones en algunos casos.
  58.  
  59.    Dentro de un segmento de código, las instrucciones incluidas pueden estar
  60. agrupadas en bloques lógicos, llamados 'procedimientos'. Estos funcionan a modo
  61. de las funciones de C o los procedimientos y funciones de Pascal. Aunque las
  62. últimas versiones de los ensambladores permiten dar listas de argumentos, va-
  63. riables locales, etc... (generando el código oportuno para manejarlos), no en-
  64. traremos en ello. Para nosotros no será más que una manera de agrupar el código
  65. en bloques lógicos, y de identificar estos bloques mediante un nombre. El nom-
  66. bre de un procedimiento entra en la tabla de símbolos, y se le asocia la di-
  67. rección de la primera instrucción después de la directiva 'PROC'.
  68.  
  69.    En el programa HELLO, tenemos un único PROC, al que llamamos 'Entrada'.
  70. Veamos las líneas detalladamente:
  71.  
  72. * mov ax,DATOS
  73.  
  74.    La etiqueta DATOS está en la tabla de símbolos, asociada al segmento de este
  75. nombre. El ensamblador genera en el '.OBJ' una referencia, que irá después en
  76. el '.EXE', de manera que esta instrucción cargue en el registro AX el valor de
  77. segmento necesario para que 'ax:0' apunte al primer byte del segmento datos.
  78. Este valor variará de una vez que se cargue el programa a otra, pero el carga-
  79. dor del DOS hace que siempre se asigne el valor correcto a AX.
  80.  
  81. * mov ds,ax
  82.  
  83.    Hace que DS, efectivamente, apunte al segmento de código del programa. Así,
  84. podremos acceder a la cadena contenida en este segmento.
  85.  
  86. * mov dx, OFFSET Msg
  87.  
  88.    Carga DX con el offset de la etiqueta Msg dentro de su segmento. Ya que Msg
  89. está al principio del segmento, dx se cargará con el valor 0. Aunque el progra-
  90. ma pueda cargarse en cualquier punto de la memoria, el offset de algún dato o
  91. alguna instrucción dentro de su segmento será siempre el mismo, por lo que esta
  92. instrucción no se incluye en la tabla de reubicación del '.EXE'.
  93.  
  94. * mov ah,9
  95. * int 21h
  96.  
  97.    Se invoca el servicio 9 de la interrupción 21h del DOS. Este servicio escri-
  98. en la pantalla la cadena apuntada por DS:DX (que en este caso será la cadena
  99. Msg). Se retorna al encontrar el carácter '$', que no se imprime. Podemos apre-
  100. ciar que en el segmento DATOS aparece el símbolo '$' dentro de la propia
  101. cadena.
  102.  
  103. * mov ax,4C00h
  104. * int 21h
  105.  
  106.    Se invoca el servicio 4Ch de la interrupción 21h. Este servicio retorna al
  107. programa que invocó al programa actual (normalmente al COMMAND.COM), con un
  108. nivel de error ('ERRORLEVEL') especificado en el registro AL. En este caso, se
  109. retorna el valor 0 (que habitualmente indica ausencia de errores).
  110.  
  111.    Después de cerrar el procedimiento 'Entrada' y el segmento 'CODIGO', encon-
  112. tramos una última directiva, 'END', con el nombre del procedimiento como pará-
  113. metro. Esta directiva puede llevar un único parámetro, opcional, que indica el
  114. punto de entrada al programa. En caso de linkar varios '.OBJ' para generar un
  115. ejecutable, sólo uno de ellos puede especificar punto de entrada (pero necesa-
  116. riamente alguno debe especificarlo), por lo que el resto de los módulos termi-
  117. nan su listado con un simple 'END'. En este caso, ya que 'Entrada' se asocia a
  118. la primera instrucción del procedimiento, el punto de entrada es la instrucción
  119. 'mov ax,DATOS'.
  120.  
  121.    Antes de pasar a ver las directivas simplificadas de segmento, veamos un
  122. punto importante de los ensambladores. Los ensambladores comerciales llevan
  123. incorporado un evaluador de expresiones, de manera que en cualquier lugar donde
  124. el ensamblador espere una constante puede aparecer una expresión que pueda
  125. evaluarse en tiempo de ensamblado. Estas expresiones pueden llevar operadores;
  126. podremos encontrar una lista de todos en el manual del ensamblador o en la ayu-
  127. da online. Los más importantes son los siguientes:
  128.  
  129.    +,-,*,/,MOD       Aritméticos
  130.    OR, AND, XOR, NOT Lógicos
  131.    SEG, OFFSET       Aplicados a una etiqueta, dan el valor de segmento donde
  132.                      reside (se incluye una entrada en la tabla de relocaliza-
  133.                      ción) y el offset dentro de su segmento
  134.    SHL, SHR          Sintáxis: X SHL Y. Devuelve el valor X desplazado a la
  135.                      izquierda (derecha) Y bits.
  136.    ()                Se utilizan para saltarse la precedencia de operadores
  137.  
  138.    Líneas válidas utilizando estos operadores son las siguientes (suponiendo
  139. que todas las etiquetas hayan sido definidas previamente):
  140.  
  141.     Msg      DW 55h SHR 2
  142.     Variable DB 15 + OFFSET Msg
  143.     mov ax,4+3*OFFSET Msg
  144.     mov dx,2 + NOT 01010101b
  145.     add ax,es:[bx+di+1+OFFSET Msg]
  146.     sub si,(2Ah+13d)*2
  147.  
  148.    Son todas válidas porque las expresiones que aparecen puede evaluarlas el
  149. propio ensamblador para obtener valores numéricos. Las siguientes instruccio-
  150. nes, en cambio, aunque perfectamente inteligibles, son ilegales y el ensambla-
  151. dor se quejará si las incluímos:
  152.  
  153.     mov ax,2+bx
  154.     add dx,bx*ax
  155.     mov cx,NOT dx
  156.  
  157.    Veamos ahora una versión del programa anterior utilizando las directivas de
  158. segmento simplificadas. Veamos cómo se simplifica mucho:
  159.  
  160. =================8<============================8<===========================
  161. .MODEL SMALL    ; Un segmento de código, otro con los datos y la pila
  162. .STACK 200h        ; 200h (512d) bytes de pila
  163. .DATA            ; Abre el segmento de datos
  164. Msg    DB 'Hello, world!$'
  165.  
  166. .CODE            ; Abre el segmento de código, cierra el de datos
  167. Entrada    PROC    ; Abre el procedimiento 'Entrada'
  168.     mov    ax,@data
  169.     mov    ds,ax
  170.     mov    dx,OFFSET Msg
  171.     mov    ah,9
  172.     int    21h        ; Servicio 9: imprimir cadena
  173.     mov    ax,4C00h
  174.     int    21h        ; Servicio 4Ch: retorno al DOS
  175. Entrada    ENDP    ; Cierra el procedimiento 'Entrada'
  176.  
  177.     END Entrada    ; Fin del programa (punto de entrada 'Entrada'), cierra
  178.                 ; el segmento de código
  179. =================8<============================8<===========================
  180.  
  181.    Las nuevas directivas utilizadas son las que comienzan con un punto. La
  182. primera, '.MODEL', especifica el modelo de memoria que se va a utilizar. En
  183. función de el modelo de memoria se seleccionan los nombres de los segmentos, de
  184. manera que se pueda linkar el módulo con otro módulo escrito en un lenguaje de
  185. alto nivel usando el mismo modelo de memoria. La directiva '.STACK' genera un
  186. segmento de pila, de 1024 bytes en caso de que no se especifique el tamaño. La
  187. directiva '.DATA' abre el segmento de datos, cerrando el segmento anterior en
  188. caso de que haya alguno abierto. La directiva '.CODE' abre el segmento de códi-
  189. go, cerrando (en este caso) el segmento de datos. Por fin, la directiva 'END'
  190. es ampliada para cerrar el segmento abierto cuando aparece, en este caso el
  191. segmento de código.
  192.  
  193.    Ya que no sabemos el nombre que da el ensamblador a los distintos segmentos,
  194. existen algunos símbolos que se definen automáticamente al encontrar la direc-
  195. tiva '.MODEL'. Estos símbolos representan el nombre de los distintos segmentos
  196. generados, y son dos: @code y @data. Por eso, en la primera instrucción carga-
  197. mos DS con @data, para poder acceder a 'Msg', que está en el segmento dado por
  198. '.DATA'.
  199.  
  200.    El propio ensamblador genera el 'ASSUME...' al encontrar la directiva
  201. '.CODE'. Como vemos, no es necesario preocuparse por casi nada al usar las
  202. directivas simplificadas de segmento. De hecho, ya no es habitual encontrar
  203. programas escritos con las directivas antiguas. Estas directivas se añadieron
  204. para facilitar el desarrollo de programas con módulos en distintos lenguajes,
  205. ya que la tarea se complica mucho usando las directivas clásicas.
  206.  
  207.    En el siguiente capítulo veremos el último concepto que nos queda por ver
  208. de microprocesadores: los flags. Veremos algunas instrucciones nuevas y alguna
  209. interrupción nueva, viéndolo todo con un pequeño programa de ejemplo. De aquí
  210. en adelante, iremos cubriendo distintos temas progresivamente, de manera que
  211. se vean ejemplos de todos los usos habituales del lenguaje ensamblador. De
  212. esta manera, aunque el curso no será muy útil como referencia de ASM, quien
  213. lo siga habrá visto la mayoría de los aspectos del ASM y podrá abordar cual-
  214. quier proyecto en este lenguaje, que es cuando realmente adquirirá verdadero
  215. dominio del lenguaje. Os recomiendo que os hagáis al menos con dos manuales o
  216. guías de referencia: una con las instrucciones del 80x86, y otra con las
  217. interrupciones de la BIOS y el MSDOS. Sobre las instrucciones no me atrevo a
  218. recomendar ninguna, mientras que sobre las interrupciones tenéis por ahí unos
  219. documentos, escritos por Ralph Brown, denominados INTERxxA.ARJ, INTERxxB.ARJ e
  220. INTERxxC.ARJ (xx es la versión, la última es la 33, creo) con la más completa
  221. referencia de interrupciones que existe (son muchos megas de texto!). Son de
  222. dominio público, por lo que las encontraréis en bastantes BBS. Ahí tendréis
  223. todo lo que queráis saber sobre los usos de las diferentes interrupciones.
  224.  
  225.    Salut :-)
  226.  
  227.    Jon